<?php
namespace app\app\Controller\v1;
use think\Db;
use think\Request;
use app\app\util\OnlineUtils;
use app\app\util\RedPacketUtils;

class RedPacketController extends BaseController{

    /**
     * 显示资源列表
     * 红包列表
     * @return \think\Response
     */
    public function index()
    {

    }

    /**
     * 显示创建资源表单页.
     *
     * @return \think\Response
     */
    public function create()
    {

    }

    /**
     * 保存新建的资源
     * 发红包
     * @param string total_fee 总金额
     * @param int num 数目
     */
    public function save()
    {
    	$user_id = OnlineUtils::getUserIdBySid();
    	$user = Db::name('users')->where('id','eq',$user_id)->find();
    	if($user['fee'] < intval(input('post.total_fee'))*100){
    		return hmp(402,'余额不足');
    	}
    	//余额充足
    	$packet  = array();
    	$total_fee = input('post.total_fee') ? input('post.total_fee') : 0;
    	$packet['total_fee'] = $total_fee*100;
    	$packet['num'] = input('post.num') ? input('post.num') : 0;
    	$packet['surplus_fee'] = $total_fee*100;
    	$packet['surplus_num'] = input('post.num') ? input('post.num') : 0;
    	$packet['create_time'] = date('Y-m-d H:i:s',time());
    	$time = strtotime('+1 day');
    	$packet['lose_time']   = date('Y-m-d H:i:s',$time);
    	//插入数据库
    	$id = Db::name('red_packet')->insertGetId($packet);
    	if($id){
    		//取出红包
    		$packet = Db::name('red_packet')->where('id','eq',$id)->find();
    		//生成随机包
    		$num   = intval($packet['num']);
    		$total = intval($packet['total_fee'])/100;
    		$min   = 0.01;
    		$data  = array();
		    for ($i=1;$i<$num;$i++)   
		    {   
		        $safe_total=($total-($num-$i)*$min)/($num-$i);//随机安全上限   
		        $money=mt_rand($min*100,$safe_total*100)/100;   
		        $total=$total-$money;
		        //插入数据库
		        db('recieve_packet')->insert(array('user_id'=>'','packet_id'=>$id,'fee'=>$money*100,'create_time'=>date('Y-m-d H:i:s',time())));
		        //把红包放入缓存
    			RedPacketUtils::createRedPacket($id,$money);
		        // 返回数据  
		        $data[$i]['money']   = $money;
		        $data[$i]['surplus'] = $total;
		    }  
			//加上最后一个
			$num_1 = $num - 1;
			$data[$num]['money'] = $data[$num_1]['surplus'];
			$data[$num]['surplus'] = 0;
		    db('recieve_packet')->insert(array('user_id'=>'','packet_id'=>$id,'fee'=>($data[$num]['money'])*100,'create_time'=>date('Y-m-d H:i:s',time())));
		    //把红包放入缓存
    		RedPacketUtils::createRedPacket($id,$data[$num]['money']);
		
    		$packet_arr = $data;
    		//扣除余额
    		$fee = intval($packet['total_fee']);
    		Db::query('update hmp_users set fee = fee -'.$fee.' where id = '.$user_id);
    		return hmp(200,'success',['data'=>$packet_arr]);
    	}else{
    		return hmp(402,'fail');
    	}
    }

    /**
     * [recieveRedPacket 领红包]
     * @return [json] 
     */
    public function recieveRedPacket()
    {
    	$user_id = OnlineUtils::getUserIdBySid();
    	$packet_id = input('get.id')?input('get.id') : 0;
    	//查询是否已领取
    	$packet_arr = RedPacketUtils::getUserRedPacketId($user_id);
    	if($packet_arr && in_array($packet_id,$packet_arr)){
    		return hmp(402,'已经领取该红包');
    	}
    	//未领取
    	$packet  = Db::name('red_packet')->where('id','eq',$packet_id)->where('status','eq',1)->find();
    	//红包存在且数量充足
    	if($packet && $packet['num'] > 1){
	    	//取出红包数组
	    	$packet_arr = RedPacketUtils::createRedPacket($packet_id,$fee='',$type=1);
	    	//随机取出一个红包
	    	$fee_k  = array_rand($packet_arr,1);
			$fee  = $packet_arr[$fee_k]*100;
	    	//数据库找出一个金额等于$fee的数据
	    	$packet_recieve = current(Db::name('recieve_packet')->where('fee','eq',intval($fee))->where('packet_id','eq',$packet_id)->where('status','eq',1)->select());
    		//修改状态
    		$time = date('Y-m-d',time());
    		Db::query('update hmp_recieve_packet set status = 2,user_id = '.$user_id.' where id ='.$packet_recieve['id']);
    		//为该用户增加余额
    		Db::query('update hmp_users set fee = fee + '.intval($fee).' where id = '.$user_id);
    		//修改红包剩余数
    		Db::query('update hmp_red_packet set surplus_num = surplus_num - 1,surplus_fee = surplus_fee - '.intval($fee).' where id = '.$packet_id);
    		//减少redis红包数目
    		RedPacketUtils::createRedPacket($packet_id,$fee/100,$type=2);
			//已领红包ID存入缓存
			RedPacketUtils::getUserRedPacketId($user_id,$packet_id);
    		//返回
    		$surplus = Db::name('red_packet')->where('id','eq',$packet_id)->where('status','eq',1)->find();
    		$data['fee'] = $fee/100;
    		$data['num'] = $surplus['num'];
    		$data['surplus_num'] = $surplus['surplus_num'];
    		$data['surplus_fee'] = $surplus['surplus_fee']/100;
    		return hmp(200,'success',['data'=>$data]);
    	}else{
    		return hmp(402,'领取失败');
    	}
    }

    /**
     * 显示指定的资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function read($id)
    {

    }

    /**
     * 显示编辑资源表单页.
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * 保存更新的资源
     *
     * @param  \think\Request  $request
     * @param  int  $id
     * @return \think\Response
     */
    public function update($id)
    {

    }

    /**
     * 删除指定资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function delete($id)
    {

    }

    //微信统一下单
    public function WeChatOrder()
    {
        $user_id = OnlineUtils::getUserIdBySid();
		$user = OnlineUtils::getUserInfoBySid();
        $openid = $user['wx_openid'];
        //下单
        $order['pay_way'] = "WeChat Pay";
        $order['user_id'] = $user_id;
		$order['order_number'] = OnlyOneOrderNumber();
        //购买的商品id
        $gear_id = input('post.gear_id') ? input('post.gear_id') : 0; 	
        //费用
        $gear  = Db::name('recharge_gear')->where('id','eq',intval($gear_id))->find(); 
        if(!$gear){
            return hmp(402,'fail');
        }
		$order['gear'] = $gear_id;
        //订单费用
        $order['total_fee'] = $gear['charge'];           
        //订单生成时间
        $order['create_time'] = date('Y-m-d H:i:s',time());
        //插入表
        $order_id = Db::name('orders')->insertGetId($order);
        $body   = "红名片余额充值";
        //查询订单表
        $orders = Db::name('orders')->where('id','eq',$order_id)->where('status','eq',1)->find();
        $order_number = $orders['order_number'];
        $total_fee = $orders['total_fee'];
        $data = array(
            'appid'=>config('APPID'),
            'mch_id'=>config('MCH_ID'),
            'body'=>$body,
            'out_trade_no'=>$order_number,
            'total_fee'=>intval($total_fee),
            'spbill_create_ip'=>$_SERVER["REMOTE_ADDR"],
            'trade_type'=>'JSAPI',
			'openid'=>$openid,
			'sign_type'=>'MD5'
        );
        $post_data = $this->setSendData($data);
        // return hmp(200,'success',$post_data);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $xml_data = $this->senXml($url,$post_data);
        // return hmp(200,'success',$xml_data);
       //解析返回数据
        $postObj = $this->xmlToObject($xml_data);
        if ($postObj === false) {
            return hmp(402,'false');
            exit;             // 如果解析的结果为false，终止程序
        }
        if ($postObj->return_code == 'FAIL') {
             return hmp(402,'fail123',$postObj->return_msg);            // 如果微信返回错误码为FAIL，则代表请求失败，返回失败信息；
        } else {
            //如果上一次请求成功，那么我们将返回的数据重新拼装，进行第二次签名
            $resignData = array(
                'appId'       =>    $postObj->appid,
                'nonceStr'    =>    $postObj->nonce_str,
				'signType'    =>    'MD5',
                'timeStamp'   =>    time(),
                'package'     =>    'prepay_id='.$postObj->prepay_id
            );
            //二次签名；
            $sign = $this->getSign($resignData);
            $resignData['sign'] = $sign;
            return hmp(200,'success',$resignData);
        }
    }

    //发送post请求(xml数据)
    private function senXml($url,$xmlData)
    {
        $header[] = "Content-type: text/xml"; //定义content-type为xml,注意是数组
        //初始化
        $ch = curl_init ($url);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
        curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
        curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch,CURLOPT_POSTFIELDS, $xmlData);
        //请求结果
        $response = curl_exec($ch);
        //返回错误
        if(curl_errno($ch)){
            print(curl_error($ch));
        }
        curl_close($ch);
        return $response;
    }


    /**
     * 生成随机数并返回
     */
    private function getNonceStr() {
        $code = "";
        for ($i=0; $i > 10; $i++) { 
            $code .= mt_rand(1000);        //获取随机数
        }
        $nonceStrTemp = md5($code);
        $nonce_str = mb_substr($nonceStrTemp, 5,37);      //MD5加密后截取32位字符
        return $nonce_str;
    }

    /**
     * 获取参数签名；
     * @param  Array  要传递的参数数组
     * @return String 通过计算得到的签名；
     */
    private function getSign($params) {
        ksort($params);        //将参数数组按照参数名ASCII码从小到大排序
        foreach ($params as $key => $item) {
            if (!empty($item)) {         //剔除参数值为空的参数
                $newArr[] = $key.'='.$item;     // 整合新的参数数组
            }
        }
        $stringA = implode("&", $newArr);         //使用 & 符号连接参数
        $stringSignTemp = $stringA."&key=".config('WX_APP_KEY');        //拼接key
                                             // key是在商户平台API安全里自己设置的
        $stringSignTemp = MD5($stringSignTemp);       //将字符串进行MD5加密
        $sign = strtoupper($stringSignTemp);      //将所有字符转换为大写
        return $sign;
    }

    /**
     * 拼装请求的数据
     * @return  String 拼装完成的数据
     */
    private function setSendData($data) {
        $sTpl = "<xml>
                    <appid><![CDATA[%s]]></appid>
                    <body><![CDATA[%s]]></body>
                    <mch_id><![CDATA[%s]]></mch_id>
                    <nonce_str><![CDATA[%s]]></nonce_str>
                    <notify_url><![CDATA[%s]]></notify_url>
					<openid><![CDATA[%s]]></openid>
                    <out_trade_no><![CDATA[%s]]></out_trade_no>
					<sign_type><![CDATA[%s]]></sign_type>
                    <spbill_create_ip><![CDATA[%s]]></spbill_create_ip>
                    <total_fee><![CDATA[%d]]></total_fee>
                    <trade_type><![CDATA[%s]]></trade_type>
                    <sign><![CDATA[%s]]></sign>
                </xml>";                          //xml数据模板

        //随机数
        $nonce_str = $this->getNonceStr();
        //异步通知地址
        $notify_url = config('WX_NOTIFY_URL');
        //将要发送的信息数组
        $data['nonce_str'] = $nonce_str;
        $data['notify_url'] = $notify_url;//将参与签名的数据保存到数组
		// return $data;
        // 注意：以上几个参数是追加到$data中的，$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
        $sign = $this->getSign($data);      //获取签名
        //替换成xml数据
        $data = sprintf($sTpl, $data['appid'], $data['body'], $data['mch_id'], $nonce_str, $notify_url, $data['openid'], $data['out_trade_no'], $data['sign_type'], $data['spbill_create_ip'], $data['total_fee'], $data['trade_type'], $sign);
        return $data;
    }

    /**
     * 解析xml文档，转化为对象
     * @param  String $xmlStr xml文档
     * @return Object         返回Obj对象
     */
    private function xmlToObject($xmlStr) {
        if (!is_string($xmlStr) || empty($xmlStr)) {
            return false;
        }
        // 由于解析xml的时候，即使被解析的变量为空，依然不会报错，会返回一个空的对象，所以，我们这里做了处理，当被解析的变量不是字符串，或者该变量为空，直接返回false
        $postObj = simplexml_load_string($xmlStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        $postObj = json_decode(json_encode($postObj));
        //将xml数据转换成对象返回
        return $postObj;
    }

   //回调地址
    public function notifyUrl()
    {
		return hmp(200,'success');    
    }

    /**
     * 查询订单状态
     * @param  Curl   $curl         工具类
     * @param  string $out_trade_no 订单号
     * @return xml               订单查询结果
     */
    public function WxQueryOrder() {
        $user_id = OnlineUtils::getUserIdBySid();
        $out_trade_no = input('order_number');
        $nonce_str = $this->getNonceStr();
        $data = array(
            'appid'         => config('WX_APP_ID'),
            'mch_id'        => config('WX_MCH_ID'),
            'out_trade_no'  => $out_trade_no,
            'nonce_str'     => $nonce_str
            );
        $sign = $this->getSign($data);
        $xml_data = '<xml>
                       <appid>%s</appid>
                       <mch_id>%s</mch_id>
                       <nonce_str>%s</nonce_str>
                       <out_trade_no>%s</out_trade_no>
                       <sign>%s</sign>
                    </xml>';
        $xml_data = sprintf($xml_data, $data['appid'], $data['mch_id'], $nonce_str, $out_trade_no, $sign);
        $url = "https://api.mch.weixin.qq.com/pay/orderquery";
        $content = $this->senXml($url,$xml_data);
        //解析xml
        $result = $this->xmlToObject($content);
        if($result->result_code == "FAIL"){
            return UiJson(402,$result->err_code_des);
        }else{
            return UiJson(200,'订单支付成功');
        }
    }
	
}